package model

import (
	"errors"
	"fmt"
	"log"
	"os"
	"time"

	"gorm.io/gorm/clause"

	"gitee.com/jason7/go_book_blog/global"
	"gitee.com/jason7/go_book_blog/pkg/setting"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
	"gorm.io/gorm/schema"
)

type Model struct {
	ID         uint32 `gorm:"primary_key" json:"id"`
	CreatedBy  string `json:"created_by"`
	ModifiedBy string `json:"modified_by"`
	CreatedOn  uint32 `json:"created_at"`
	ModifiedOn uint32 `json:"modified_at"`
	DeletedOn  uint32 `json:"deleted_at"`
	IsDel      uint8  `json:"is_del"`
}

//NewDBEngine 新DB引擎
func NewDBEngine(databaseSetting *setting.DatabaseSettingS) (*gorm.DB, error) {
	newLogger := logger.New(
		log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer（日志输出的目标，前缀和日志包含的内容——译者注）
		logger.Config{
			SlowThreshold:             time.Second,   // 慢 SQL 阈值
			LogLevel:                  logger.Silent, // 日志级别
			IgnoreRecordNotFoundError: true,          // 忽略ErrRecordNotFound（记录未找到）错误
			Colorful:                  true,          // 禁用彩色打印
		},
	)
	newLogger.LogMode(logger.Silent)

	gormConfig := &gorm.Config{
		NamingStrategy: schema.NamingStrategy{
			TablePrefix:   databaseSetting.TablePrefix, // 表名前缀，`User`表为`t_users`
			SingularTable: true,                        // 使用单数表名，启用该选项后，`User` 表将是`user`
			//NameReplacer: strings.NewReplacer("CID", "Cid"), // 在转为数据库名称之前，使用NameReplacer更改结构/字段名称。
		},
	}
	if global.ServerSetting.RunMode == "debug" {
		gormConfig.Logger = logger.Default.LogMode(logger.Info)
	}
	db, err := gorm.Open(mysql.Open(fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=%s&parseTime=%t&loc=Local",
		databaseSetting.UserName,
		databaseSetting.Password,
		databaseSetting.Host,
		databaseSetting.DBName,
		databaseSetting.Charset,
		databaseSetting.ParseTime,
	)), gormConfig)
	if err != nil {
		return nil, err
	}
	//自己定义的回调方法Register名字随意
	err = db.Callback().Create().Before("gorm:create").Register("gorm:update_time_stamp", updateTimeStampForCreateCallback)
	if err != nil {
		return nil, err
	}
	err = db.Callback().Update().Before("gorm:update").Register("gorm:update_time_stamp", updateTimeStampForUpdateCallback)
	if err != nil {
		return nil, err
	}
	//替换删除方法
	//err = db.Callback().Delete().Replace("gorm:delete", deleteCallback)
	err = db.Callback().Delete().Before("gorm:delete").Register("gorm:delete_time_stamp", deleteCallback)
	if err != nil {
		return nil, err
	}
	sqlDB, err := db.DB()
	if err != nil {
		return nil, err
	}

	sqlDB.SetMaxIdleConns(databaseSetting.MaxIdleConns) //设置空闲连接池中连接的最大数量
	sqlDB.SetMaxOpenConns(databaseSetting.MaxOpenConns) //设置打开数据库连接的最大数量
	sqlDB.SetConnMaxLifetime(time.Hour)                 //设置了连接可复用的最大时间
	return db, nil
}

//updateTimeStampForCreateCallback
func updateTimeStampForCreateCallback(db *gorm.DB) {
	db.Statement.SetColumn("CreatedOn", time.Now().Unix())
	db.Statement.SetColumn("ModifiedOn", time.Now().Unix())
	//if db.Statement.Schema != nil {
	//	currentTime := getCurrentUnixTime()
	//	err := SetSchemaFieldValue(db, "CreatedOn", currentTime)
	//	if err != nil {
	//		return
	//	}
	//	err = SetSchemaFieldValue(db, "ModifiedOn", currentTime)
	//	if err != nil {
	//		return
	//	}
	//}
}

//updateTimeStampForUpdateCallback
func updateTimeStampForUpdateCallback(db *gorm.DB) {
	db.Statement.SetColumn("ModifiedOn", time.Now().Unix())
	//if db.Statement.Schema != nil {
	//	currentTime := getCurrentUnixTime()
	//	db.Statement.SetColumn("ModifiedOn", currentTime)
	//	db.Statement.AddClause(clause.Where{
	//		Exprs: []clause.Expression{clause.Eq{Column: "deleted_on"}},
	//	})
	//}
}

//deleteCallback
func deleteCallback(db *gorm.DB) {
	if db.Error == nil {
		if db.Statement.Schema != nil {
			db.Statement.SQL.Grow(100)

			deleteField := db.Statement.Schema.LookUpField("DeletedOn")
			if !db.Statement.Unscoped && deleteField != nil {
				//Soft Delete
				if db.Statement.SQL.String() == "" {
					nowTime := time.Now().Unix()
					db.Statement.AddClause(
						clause.Set{{
							Column: clause.Column{Name: deleteField.DBName},
							Value:  nowTime,
						}},
					)
					db.Statement.AddClauseIfNotExists(clause.Update{})
					db.Statement.Build("UPDATE", "SET", "WHERE")
				}
			} else {
				//Delete
				if db.Statement.SQL.String() == "" {
					db.Statement.AddClauseIfNotExists(clause.Delete{})
					db.Statement.AddClauseIfNotExists(clause.From{})
					db.Statement.Build("DELETE", "FROM", "WHERE")
				}
			}

			//fmt.Println(db.Statement.SQL.String())
			//fmt.Println(db.Statement.Vars)

			//Must Need WHERE
			if _, ok := db.Statement.Clauses["WHERE"]; !db.AllowGlobalUpdate && !ok {
				db.AddError(gorm.ErrMissingWhereClause)
				return
			}

			db.Exec(db.Statement.SQL.String(), db.Statement.Vars...)
		}
	}
	//if db.Error == nil {
	//	if db.Statement.Schema != nil && !db.Statement.Unscoped {
	//		for _, c := range db.Statement.Schema.DeleteClauses {
	//			db.Statement.AddClause(c)
	//		}
	//	}
	//
	//	if db.Statement.SQL.String() == "" {
	//		db.Statement.SQL.Grow(100)
	//		db.Statement.AddClauseIfNotExists(clause.Delete{})
	//
	//		if db.Statement.Schema != nil {
	//			_, queryValues := schema.GetIdentityFieldValuesMap(db.Statement.ReflectValue, db.Statement.Schema.PrimaryFields)
	//			column, values := schema.ToQueryValues(db.Statement.Table, db.Statement.Schema.PrimaryFieldDBNames, queryValues)
	//
	//			if len(values) > 0 {
	//				db.Statement.AddClause(clause.Where{Exprs: []clause.Expression{clause.IN{Column: column, Values: values}}})
	//			}
	//
	//			if db.Statement.ReflectValue.CanAddr() && db.Statement.Dest != db.Statement.Model && db.Statement.Model != nil {
	//				_, queryValues = schema.GetIdentityFieldValuesMap(reflect.ValueOf(db.Statement.Model), db.Statement.Schema.PrimaryFields)
	//				column, values = schema.ToQueryValues(db.Statement.Table, db.Statement.Schema.PrimaryFieldDBNames, queryValues)
	//
	//				if len(values) > 0 {
	//					db.Statement.AddClause(clause.Where{Exprs: []clause.Expression{clause.IN{Column: column, Values: values}}})
	//				}
	//			}
	//		}
	//
	//		db.Statement.AddClauseIfNotExists(clause.From{})
	//		db.Statement.Build("DELETE", "FROM", "WHERE")
	//	}
	//
	//	if _, ok := db.Statement.Clauses["WHERE"]; !db.AllowGlobalUpdate && !ok {
	//		err := db.AddError(gorm.ErrMissingWhereClause)
	//		if err != nil {
	//			return
	//		}
	//		return
	//	}
	//
	//	if !db.DryRun && db.Error == nil {
	//		//可通过输出Vars发现参数为2021-03-04 15:56:06.256这种带有尾缀的 因此重置
	//		//db.Statement.Vars = []interface{}{time.Now().Format("2006-01-02 15:04:05")}
	//		db.Statement.Vars = []interface{}{time.Now().Unix()}
	//		result, err := db.Statement.ConnPool.ExecContext(db.Statement.Context, db.Statement.SQL.String(), db.Statement.Vars...)
	//
	//		if err == nil {
	//			db.RowsAffected, _ = result.RowsAffected()
	//		} else {
	//			err = db.AddError(err)
	//			if err != nil {
	//				return
	//			}
	//		}
	//	}
	//}
}

//addExtraSpaceIfExist
func addExtraSpaceIfExist(str string) string {
	if str != "" {
		return " " + str
	}
	return ""
}

func SetSchemaFieldValue(db *gorm.DB, fieldName string, value interface{}) error {
	field := db.Statement.Schema.LookUpField(fieldName)
	if field == nil {
		return errors.New("can't find the field")
	}
	err := field.Set(db.Statement.ReflectValue, value)
	if err != nil {
		log.Println("schema field set err:", err)
		return err
	}
	return nil
}

//getCurrentDateTime 获取当前日期时间
func getCurrentDateTime() string {
	return time.Now().Format("2006-01-02 15:04:05")
}

// getCurrentUnixTime 获取当前时间戳
func getCurrentUnixTime() int64 {
	return time.Now().Unix()
}
